/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.edu.agh.student.logic.webapp;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.log.Log;
import org.jboss.seam.security.Identity;
import org.jboss.seam.transaction.Transaction;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.TaskService;
import org.jbpm.api.task.Task;
import org.richfaces.event.UploadEvent;
import org.richfaces.model.UploadItem;

import pl.edu.agh.student.logic.service.ApplicationServiceImpl;
import pl.edu.agh.student.logic.service.UserServiceImpl;
import pl.edu.agh.student.logic.util.ServiceProvider;
import pl.edu.agh.student.model.Address;
import pl.edu.agh.student.model.Applicant;
import pl.edu.agh.student.model.Application;
import pl.edu.agh.student.model.Attachment;
import pl.edu.agh.student.model.Customer;
import pl.edu.agh.student.model.Education;
import pl.edu.agh.student.model.State;
import pl.edu.agh.student.model.User;

/**
 *
 * @author janburkot
 */
@Stateful
@Name("applicationBean")
@Scope(ScopeType.CONVERSATION)
@Transactional
public class ApplicationBeanImpl implements ApplicationBean, Serializable {

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    @In(value = "applicationService", create = true, required = false)
    @Out
    protected ApplicationServiceImpl applicationService;
    
    @In(value = "userService", create = true, required = false)
    @Out
    protected UserServiceImpl userService;

    @In(required = false, value = "applicationx")
    @Out(required = false, value = "applicationx")
    private Application application;

    @Logger
    protected Log log;
    
    @In("serviceProvider")
    ServiceProvider serviceProvider;
    
    @In
    Identity identity;
    
    @In(value = "#{facesContext.externalContext}")
    private ExternalContext extCtx;
    
    @In(value = "#{facesContext}")
    FacesContext facesContext;
    
    private Attachment file;
    
    private int uploadsAvailable = 1000;
    
    private boolean autoUpload = false;
    
    private boolean useFlash = false;

    public int getSize() {
        return getFiles().size();
    }

    @Destroy
    @Remove
    public void destroy() {
        log.debug("destry component #0", this);
    }

    public String save(Application application) {
    	applicationService.saveOrUpdate(application);
        return "success";
    }

    public String delete(Application application) {
        applicationService.delete(application);
        return "success";
    }

    public String update(Application application) {
    	System.out.println("ApplicationBean.update(): "+this.application.getName());
        applicationService.saveOrUpdate(application);
        return "success";
    }

    public List<Application> getAll() {

        if (identity.hasRole("Szef")) {
            return applicationService.getAll();
        } else if (identity.hasRole("Klient")) {
            User user = userService.findByUsername(identity.getPrincipal().getName());
            return applicationService.getCustomerApplication(user.getPerson());
        } else {
            return null;
        }
    }

    public void refresh(Application application) {
        System.out.println("ApplicationBean.refresh(): "+this.application.getName());
        applicationService.refresh(application);
    }

    public Application getSelectedApplication() {
        System.err.println(application);
        return application;
    }

    public void setSelectedApplication(Application application) {
        System.err.println(application.getId());
        System.err.println(application.getName());
        this.application = application;
    }

    public String submit(Application application) {
        try {
            //TO DO sprawdzenie czy state == FILLING
            validateApplication(application);
        } catch (Exception ex) {
            java.util.logging.Logger.getLogger(ApplicationBeanImpl.class.getName()).log(Level.SEVERE, null, ex);
            //fm.add("kod 002");
            return "failure";
        }
        
        application.setState(State.PENDING);
        applicationService.saveOrUpdate(application);
        
        System.out.println(this.application.getId());
        System.out.println(this.application.getName());
        System.out.println(application.getName());

        User user = userService.findByUsername(identity.getPrincipal().getName());
        TaskService taskService = serviceProvider.getTaskService();

        List<Task> tasks = taskService.findPersonalTasks(user.getUsername());
        System.out.println(tasks);


        Task currentTask = null;
        for (Task t : tasks) {
            Long var = (Long) taskService.getVariable(t.getId(), "applicationId");
            System.out.println(var.longValue() + " " + application.getId());
            if (var.longValue() == application.getId().longValue()) {
                currentTask = t;
                break;
            }

        }

        taskService.completeTask(currentTask.getId(), "send");
        return "success";
    }

    public String create() {
        
        User user = userService.findByUsername(identity.getPrincipal().getName());
        
        if(!isCustomer(user)){
            facesContext.addMessage("asfd", new FacesMessage("asfas"));
            return "failure";
        }
        
        application = new Application();
        Calendar cal = Calendar.getInstance();
        application.setName("Wniosek - " + sdf.format(cal.getTime()));
        application.setPerson(user.getPerson());
        application.setState(State.NEW);
        
        tryFill(application, user.getPerson());

    	applicationService.saveOrUpdate(application);
    	
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("applicationId", application.getId());
        //variables.put("user", "xxx"); //nie wiem po co

        ProcessInstance process = serviceProvider.getExecutionService().startProcessInstanceByKey("credit");
        serviceProvider.getExecutionService().createVariables(process.getId(), variables, true);

        List<Task> tasks = serviceProvider.getTaskService().findGroupTasks(user.getUsername());
        System.out.println(tasks);

        TaskService taskService = serviceProvider.getTaskService();
        Task currentTask = null;
        for (Task t : tasks) {
            Long var = (Long) taskService.getVariable(t.getId(), "applicationId");
            System.out.println(var.longValue() + " " + application.getId());
            if (var.longValue() == application.getId().longValue()) {
                currentTask = t;
                break;
            }

        }
        
        serviceProvider.getTaskService().takeTask(currentTask.getId(), user.getUsername());
//        try{
//            serviceProvider.getTaskService().takeTask(currentTask.getId(), user.getUsername());
//        }
//        catch(Exception e){
//            facesContext.addMessage("asfd", new FacesMessage("asfas"));
//            return "failure";
//        }
        
        return "success";
    }

    public String delete(){
        TaskService taskService = serviceProvider.getTaskService();
        
        if(this.getSelectedApplication() != null){
            User user = userService.findByUsername(identity.getPrincipal().getName());
            List<Task> tasks = taskService.findPersonalTasks(user.getUsername());
            System.out.println(tasks);


            Task currentTask = null;
            for (Task t : tasks) {
                Long var = (Long) taskService.getVariable(t.getId(), "applicationId");
                System.out.println(var.longValue() + " " + application.getId());
                if (var.longValue() == application.getId().longValue()) {
                    currentTask = t;
                    break;
                }

            }
            
            
            applicationService.delete(application);
            if(currentTask != null){
                String execId = currentTask.getExecutionId();
                serviceProvider.getExecutionService().deleteProcessInstanceCascade(currentTask.getExecutionId());
                //serviceProvider.getExecutionService().signalExecutionById(currentTask.getExecutionId(), "send");
                
                List<Task> ts = serviceProvider.getTaskService().createTaskQuery().processInstanceId(currentTask.getExecutionId()).list();
                
                for(Task t: ts){
                    System.out.println(t);
                    serviceProvider.getTaskService().deleteTask(t.getId(), "");
                }
                
            }
        }
        return "success";
    }
    
    private void tryFill(Application application, Customer customer){
        if(application == null || customer == null){
            return;
        }
        
        Applicant applicant = application.getApplicant();
        applicant.setFirstname(customer.getFirstname());
        applicant.setLastname(customer.getLastname());
        
        Address address = applicant.getAddress();
        address.setStreet(customer.getAddress().getStreet());
        address.setPostcode(customer.getAddress().getPostcode());
        address.setCity(customer.getAddress().getCity());
        
        applicant.setPesel(customer.getPesel());
        
    }
    public void paint(OutputStream stream, Object object) throws IOException {
        stream.write(getFile().getData());
    }

    public void listener(UploadEvent event) throws Exception {
        UploadItem item = event.getUploadItem();
        Attachment _file = new Attachment();
        _file.setLength(item.getData().length);
        _file.setName(item.getFileName());
        _file.setData(item.getData());

        applicationService.addAttachment(_file, application);
    }

    public long getTimeStamp() {
        return System.currentTimeMillis();
    }

    public int getUploadsAvailable() {
        return uploadsAvailable;
    }

    public void setUploadsAvailable(int uploadsAvailable) {
        this.uploadsAvailable = uploadsAvailable;
    }

    public boolean isAutoUpload() {
        return autoUpload;
    }

    public void setAutoUpload(boolean autoUpload) {
        this.autoUpload = autoUpload;
    }

    public boolean isUseFlash() {
        return useFlash;
    }

    public void setUseFlash(boolean useFlash) {
        this.useFlash = useFlash;
    }

    public Attachment getFile() {
        return file;
    }

    public void setFile(Attachment file) {
        this.file = file;
    }

    public List<Attachment> getFiles() {
        List<Attachment> files = new LinkedList<Attachment>();
        files.addAll(application.getAttachments());
        return files;
    }

    @Factory
    public Education[] getEducation() {
        return Education.values();
    }

    public void delete(Attachment _file) {
        applicationService.removeAttachment(_file, application);
    }

    public String download(Attachment _file) {

        HttpServletResponse response = (HttpServletResponse) extCtx.getResponse();
        String ct = _file.getContentType();
        if(ct != null){
            ct = "application/octet-stream";
        }
        response.setContentType(ct);
        response.addHeader("Content-disposition", "attachment; filename=\"" + _file.getName() + "\"");
        try {
            ServletOutputStream os = response.getOutputStream();
            os.write(_file.getData());
            os.flush();
            os.close();
            facesContext.responseComplete();
        } catch (Exception e) {
            log.error("\nFailure : " + e.toString() + "\n");
        }

        return null;
    }
    
    public boolean isSubmited(Application app){
        return !State.NEW.equals(app.getState());
    }
    
    public boolean isOwner(Application app){
        User user = userService.findByUsername(identity.getPrincipal().getName());
        System.out.println(identity.getPrincipal().getName());
        System.out.println("++++++++User "+user);
        System.out.println(user);
        System.out.println(app);
        System.out.println(user.getId());
        System.out.println(app.getPerson());
        return user.getId().longValue() == app.getPerson().getUser().getId().longValue();
    }
    
    public void validateApplication(Application app) throws Exception{
        boolean result = true;
        result = result && (application.getAmount() != null);
        System.out.println(result);
        result = result && (application.getApplicant().getFirstname() != null);
        System.out.println(result);
        result = result && (application.getApplicant().getLastname() != null);
        System.out.println(result);
        result = result && (application.getApplicant().getEducation() != null);
        System.out.println(result);
        result = result && (application.getApplicant().getPesel() != null);
        System.out.println(result);
        result = result && (application.getApplicant().getAddress().getStreet() != null);
        System.out.println(result);
        result = result && (application.getApplicant().getAddress().getPostcode() != null);
        System.out.println(result);
        result = result && (application.getApplicant().getAddress().getCity() != null);
        System.out.println(result);
        
        
        if(!result)
            throw new Exception("asdfas");
    }

    private boolean isCustomer(User user) {
        System.out.println("isCustomer(User user)");
        System.out.println(user.getPerson());
        return user.getPerson() != null;
    }
}
